from src.env import Env
from src.session import Session
from src.settings import FileSettings, MergedSettings
import os
import click
import time, datetime
import shutil
from src.vault import Credentials

env = Env()

assert env.PHILLY_ROOT != env.CUR_DIR, "Please do not run philly in PHILLY_ROOT!"


@click.group()
def cli():
    pass

def read_settings():
    # global settings
    global_settings_file = os.path.join(env.PHILLY_ROOT, '.philly', 'settings')
    global_settings = FileSettings(global_settings_file)

    # local settings
    local_settings_file = os.path.join(env.CUR_DIR, '.philly', 'settings')
    local_settings = FileSettings(local_settings_file)

    settings = MergedSettings([local_settings, global_settings]) 
    return settings, local_settings, global_settings

@cli.command()
def init():
    local_settings_dir = os.path.join(env.CUR_DIR, '.philly')
    local_settings_file = os.path.join(env.CUR_DIR, '.philly', 'settings')
    if os.path.exists(local_settings_dir):
        confirm = click.confirm(".philly/ exists, remove it?")
        if not(confirm):
            return
        shutil.rmtree(local_settings_dir)
    FileSettings.make_if_not_exists(env.CUR_DIR)
    local_settings = FileSettings(local_settings_file)

    name_to_set = os.path.split(env.CUR_DIR)[-1].strip()
    local_settings.set('name', name_to_set)
    click.echo('Set name to: {}'.format(name_to_set))

    click.echo('Initialized.')


@cli.command()
def convert():
    settings, local_settings, global_settings = read_settings()

    dirname = 'model'
    origin_dirname = os.path.join('ModelToTest', 'origin')
    filenames = os.listdir(dirname)
    new_dirname = os.path.join(
                    'ModelToTest',
                    '{}_{}'.format(
                    settings.get('converter_add_name'),
                    env.CUR_TIME_STR,
    ))
    if len(filenames) != 0:
        with open('convert.bat', 'w') as f:
            f.write('activate {} '.format(settings.get('converter_env')))
            for filename in filenames:
                if '-Iter' in filename:
                    click.echo("Skip {}".format(filename))
                    continue
                # copy the model to orign_dirname
                if not(os.path.exists(origin_dirname)):
                    os.makedirs(origin_dirname)
                shutil.copy(
                    os.path.join(dirname, filename),
                    os.path.join(origin_dirname, filename)
                )
                # construct bat file
                new_filename = settings.get('name') + "_" + filename + '.mdl'
                if not(os.path.exists(new_dirname)):
                    os.makedirs(new_dirname)
                f.write(' && python {} CntkToCoreLib {} {} -t Simple -e {}'.format(
                    settings.get('converter_path'),
                    os.path.join(origin_dirname, filename),
                    os.path.join(new_dirname, new_filename),
                    settings.get('target_node'),
                ))
            f.write('\npause')
            if os.path.exists('bat'):
                pass
            # os.system('.\\convert.bat')
    else:
        click.echo('No File Founded!')


@cli.command()
@click.argument('name_to_set', default="")
def name(name_to_set):
    settings, local_settings, global_settings = read_settings()
    if name_to_set == "":
        name_to_set = os.path.split(env.CUR_DIR)[-1].strip()
    local_settings.set('name', name_to_set)
    click.echo('Set name to: {}'.format(name_to_set))

@cli.command()
@click.option('--all', is_flag=True)
def status(all):
    settings, local_settings, global_settings = read_settings()
    if local_settings.has('name'):
        click.echo('Current name: {}'.format(local_settings.get('name')))
    else:
        click.echo('No name has been set.')
    click.echo('')
    click.echo('[Local Settings]')
    if all:
        click.echo('[Local settings file: {}]'.format(local_settings.settings_path))
    keys = sorted(local_settings.settings.keys())
    for key in keys:
        click.echo('{} = {}'.format(key, local_settings.get(key)))
    click.echo('')
    click.echo('[Global Settings]')
    if all:
        click.echo('[Global settings file: {}]'.format(global_settings.settings_path))
    keys = sorted(global_settings.settings.keys())
    for key in keys:
        click.echo('{} = {}'.format(key, global_settings.get(key)))

@cli.command()
@click.argument('key')
@click.argument('value')
def set(key, value):
    settings, local_settings, global_settings = read_settings()
    local_settings.set(key, value)
    click.echo('Set local settings {} to {}.'.format(key, value))

@cli.command()
@click.argument('key')
@click.argument('value')
def set_global(key, value):
    settings, local_settings, global_settings = read_settings()
    global_settings.set(key, value)
    click.echo('Set global settings {} to {}.'.format(key, value))


@cli.command()
@click.argument('value')
def connect(value):
    settings, local_settings, global_settings = read_settings()
    local_settings.set('taskId', value)
    click.echo('Set local settings taskId to {}.'.format(value))

@cli.group()
def model():
    pass

@model.command('ls')
def model_ls():
    settings, local_settings, global_settings = read_settings()
    cmd = 'philly-fs -ls //philly/{}/{}/sys/jobs/application_{}/models'.format(
        settings.get('clusterId'),
        settings.get('vcId'),
        settings.get('taskId'),
    )
    click.echo('use command: {}'.format(cmd))
    os.system(cmd)

@model.command('d')
@click.argument('values', nargs=-1)
def model_download(values):
    settings, local_settings, global_settings = read_settings()
    model_dir = os.path.join(env.CUR_DIR, 'model')
    if not(os.path.exists(model_dir)):
        os.makedirs(model_dir)
    
    i = 0
    for value in values:
        cmd = 'philly-fs -cp //philly/{}/{}/sys/jobs/application_{}/models/{} ./model'.format(
            settings.get('clusterId'),
            settings.get('vcId'),
            settings.get('taskId'),
            value,
        )
        click.echo('use command: {}'.format(cmd))
        ret = os.system(cmd)
        click.echo(ret)

@cli.group()
def log():
    cert = os.path.join(env.PHILLY_ROOT, "./philly/ms-internal-root.crt")
    Credentials.instantiate(username="", insecure=False, cert=cert,
                          domain_joined=True)
    cred = Credentials.get(True)


@log.command('d')
@click.argument('values', nargs=-1)
def log_download(values):
    if len(values) == 0:
        values = ['latest']
    settings, local_settings, global_settings = read_settings()
    from src.manager import PhillyManager
    job_mgr = PhillyManager(vc=settings.get('vcId'), cluster=settings.get('clusterId'))
    log_dir = os.path.join(env.CUR_DIR, "log/")
    os.makedirs(log_dir, exist_ok=True)
    for value in values:
        ret = job_mgr.curl('log', vcId=settings.get('vcId'), jobId="application_" + settings.get('taskId'),
                     clusterId=settings.get('clusterId'), jobType='cust',
                     logType='log', logRev=value,
                     content='full')
        log_filename = os.path.join(log_dir, '{}.txt'.format(value))
        with open(log_filename, 'w') as f:
            f.write(ret)
            click.echo('Successfully write to {}, log length {}.'.format(log_filename, len(ret)))

@log.command('a')
@click.argument('values', nargs=-1)
@click.pass_context
def log_analysis(ctx, values):
    import re
    import traceback
    if len(values) == 0:
        values = ['latest']
    log_dir = os.path.join(env.CUR_DIR, "log/")
    for value in values:
        log_filename = os.path.join(log_dir, '{}.txt'.format(value))
        if not(os.path.exists(log_filename)):
            click.echo('Downloading log: {}'.format(value))
            ctx.invoke(log_download, values=[value])
        # speed
        try:
            cntkPattern = re.compile(r'[\s\S]*Epoch[\s\S]*-Minibatch[\s\S]* time = (\d*\.?\d+)s;[\s\S]*')
            with open(log_filename, 'r') as f:
                cnt = 0
                totalTime = 0
                for line in f:
                    result = re.match(cntkPattern, line)
                    if(result):
                        usedTime = float(result.group(1))
                        totalTime += usedTime
                        cnt += 1
            print('{}.txt Speed: {:4f} seconds / 100 iter'.format(value, float(totalTime) / cnt))
        except Exception:
            click.echo('Error when analyze {}. More Info:'.format(log_filename))
            traceback.print_exc()
        # error and accuracy
        try:
            cePattern = re.compile(r'.*Finished Epoch\[(.*) of .*\]: \[Training\] ce = (.*) \* \d*;.*')
            with open(log_filename, 'r') as f:
                for line in f:
                    result = re.match(cePattern, line)
                    if result:
                        click.echo('{}.txt Epoch {} ce: {}'.format(value, result.group(1).strip(), result.group(2).strip()))
        except Exception:
            click.echo('Error when analyze {}. More Info:'.format(log_filename))
            traceback.print_exc()
        click.echo('')





@cli.command()
def test():
    os.system('philly-fs')